home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
biblio
/
bibtex
/
utils
/
bibclean
/
strtol.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-06
|
5KB
|
259 lines
/* -*-C-*- strtol.c */
/*-->strtol*/
/**********************************************************************/
/****************************** strtol ********************************/
/**********************************************************************/
#include "os.h"
#include "xctype.h"
#include "xstring.h"
#include "xstdlib.h"
RCSID("$Id: strtol.c,v 1.6 1992/10/08 01:42:01 beebe Exp beebe $")
/* $Log: strtol.c,v $
* Revision 1.6 1992/10/08 01:42:01 beebe
* Update for C++.
*
* Revision 1.5 1992/07/10 17:58:12 beebe
* Modify one output format.
*
* Revision 1.4 1992/03/06 14:58:06 beebe
* Complete two-month long development of version 3.0.114. See
* 00revhst.txt for details.
*
* Revision 1.3 1992/02/29 19:42:20 beebe
* Update for version 3.0.114 [29-Feb-1992] following two-month
* major overhaul and compilation testing on numerous machines.
*
* Revision 1.2 1992/01/22 02:31:19 beebe
* Add RCSID() and RCS comment log.
* */
#define IN(l,a,r) (((l) <= (a)) && ((a) <= (r)))
/* This is a simple implementation of Standard C strtol(). A library
version should be programmed with more care. */
long
#if STDC
strtol(
const char *nptr,
char** endptr,
int base
)
#else /* NOT STDC */
strtol(nptr,endptr,base)
const char *nptr;
char** endptr;
int base;
#endif /* STDC */
{
int c; /* current character value */
int digit; /* digit value */
static const char *digits = "0123456789abcdefghijklmnopqrstuvxwyz";
int negative; /* 0 for positive, non-0 for negative */
long number; /* the accumulating number */
const char *pos; /* pointer into digit list */
const char *q; /* pointer past end of digits */
if (!(IN(2,base,36) || (base == 0)))
{
if (endptr != (char**)NULL)
*endptr = (char*)nptr;
return (0L);
}
while (isspace(*nptr))
nptr++; /* ignore leading whitespace */
switch (*nptr) /* set number sign */
{
case '-':
negative = -1;
nptr++;
break;
case '+':
negative = 0;
nptr++;
break;
default:
negative = 0;
break;
}
q = nptr;
if (base == 0) /* variable base; set by lookahead */
{
if (*q == '0')
base = ((*(q+1) == 'x') || (*(q+1) == 'X')) ? 16 : 8;
else
base = 10;
}
/* eliminate optional "0x" or "0X" prefix */
if ( (base == 16) &&
(*q == '0') &&
((*(q+1) == 'x') || (*(q+1) == 'X')) )
q += 2;
number = 0L;
/* Number conversion is done by shifting rather than multiplication
when the base is a power of 2, in order that the results not be
impacted by integer overflow. */
switch (base)
{
case 2:
while (IN('0',*q,'1'))
{
number <<= 1;
number |= *q - '0';
q++;
}
break;
case 4:
while (IN('0',*q,'3'))
{
number <<= 2;
number |= *q - '0';
q++;
}
break;
case 8:
while (IN('0',*q,'7'))
{
number <<= 3;
number |= *q - '0';
q++;
}
break;
case 16:
for (;;)
{
if (!*q)
break;
c = (unsigned)*q;
if (isupper(c))
c = tolower(c);
pos = strchr(digits,c);
if (pos == (char*)NULL)
break;
digit = (int)(pos - digits);
if (!IN(0,digit,15))
break;
number <<= 4;
number |= digit;
q++;
}
break;
case 32:
for (;;)
{
if (!*q)
break;
c = (unsigned)*q;
if (isupper(c))
c = tolower(c);
pos = strchr(digits,c);
if (pos == (char*)NULL)
break;
digit = (int)(pos - digits);
if (!IN(0,digit,31))
break;
number <<= 5;
number |= digit;
q++;
}
break;
default: /* all other bases done by multiplication */
for (;;) /* accumulate negative so most negative */
{ /* number on two's-complement is handled */
if (!*q)
break;
c = (unsigned)*q;
if (isupper(c))
c = tolower(c);
pos = strchr(digits,c);
if (pos == (char*)NULL)
break;
digit = (int)(pos - digits);
if (!IN(0,digit,base-1))
break;
number *= base;
number -= digit;
q++;
}
if (endptr != (char**)NULL)
*endptr = (char*)q;
if (negative)
return(number);
number = -number;
break;
}
if (negative)
number = -number;
if (endptr != (char**)NULL)
*endptr = (char*)q;
return (number);
}
#ifdef TEST
/***********************************************************************
Simple test program for strtol(). Values are read from stdin, and the
results in different bases are echoed to stdout.
***********************************************************************/
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif /* EXIT_SUCCESS */
int
#if STDC
main(
int argc,
char *argv[]
)
#else /* NOT STDC */
main(argc,argv)
int argc;
char *argv[];
#endif /* STDC */
{
char s[25];
char *endptr;
long n;
int k;
static int base[] =
{
0, 2, 4, 8, 10, 16, 32, 36, 5,
};
while (gets(s) != (char*)NULL)
{
for (k = 0; k < sizeof(base)/sizeof(base[0]); ++k)
{
n = strtol(s,&endptr,base[k]);
(void)printf(
"strtol(,,%d): %s -> 16#%lx 8#%lo 10#%ld Rem = [%s]\n",
base[k],s,n,n,n,endptr);
}
}
exit (EXIT_SUCCESS);
return (0);
}
#endif /* TEST */